package cn.like.gateway.config;

import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.filter.SaFilterAuthStrategy;
import cn.dev33.satoken.filter.SaFilterErrorStrategy;
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.like.base.support.result.Rest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Arrays;
import java.util.Collections;

/**
 * Description: 身份验证配置过滤器
 *
 * @author like 980650920@qq.com
 * @date 2021-07-10 18:02:34
 */
@Configuration
@Slf4j
public class AuthorityAuthenticationConfigure {

    /**
     * desc: 权限验证配置，每次请求进来会执行 <br>
     */
    private SaFilterAuthStrategy getSaFilterAuthStrategy() {
        return route -> {
            // 登录验证 -> 拦截所有路由
            SaRouter.match(Collections.singletonList("/**"),
                    Arrays.asList(
                            "/sso/*", "/auth/sso/*"
                            , "/auth/login", "/like-auth-server/auth/login"
                            , "/auth/signUp", "/like-auth-server/auth/signUp"
                            , "/auth/createCaptcha/**", "/like-auth-server/auth/createCaptcha/**"
                    ), StpUtil::checkLogin);

            // other  SaRouter.match(xxx)
        };
    }

    /**
     * desc: 权限校验失败会执行 <br>
     */
    private SaFilterErrorStrategy getSaFilterErrorStrategy() {
        return e -> {
            if (e instanceof NotLoginException)
                return Rest.of().msg(e.getMessage()).code(Long.parseLong(((NotLoginException) e).getType()));
            return Rest.failed(e.getMessage());
        };
    }

    /**
     * 注册 [Sa-Token全局过滤器]
     */
    @Bean
    public SaReactorFilter getSaReactorFilter() {
        return new SaReactorFilter()
                .addInclude("/**")
                .addExclude("/favicon.ico")
                .addExclude("/doc.html/**")
                .addExclude("/swagger-resources/**")
                .addExclude("/**/swagger-resources/**")
                .addExclude("/webjars/**")
                .addExclude("/**/webjars/**")
                .addExclude("/v2/**")
                .addExclude("/**/v2/**")
                .addExclude("/swagger-ui.html/**")
                .addExclude("/**/swagger-ui.html/**")
                .addExclude("/actuator/**")
                .addExclude("/**/actuator/**")
                // 前置函数：在每次认证函数之前执行
               .setBeforeAuth(getFilterBeforeAuthStrategy())
                // 认证函数: 每次请求执行
                .setAuth(getSaFilterAuthStrategy())
                // 认证失败，调用此函数
                .setError(getSaFilterErrorStrategy());
    }

    private SaFilterAuthStrategy getFilterBeforeAuthStrategy() {
        return r -> {

            log.info("[ 网关权限认证 ] - 拦截到请求 :{}", SaHolder.getRequest().getRequestPath());

            // ---------- 设置一些安全响应头 ----------
            SaHolder.getResponse()
                    // 服务器名称
                    .setServer("like-server")
                    // 是否可以在iframe显示视图： DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
                    .setHeader("X-Frame-Options", "SAMEORIGIN")
                    // 是否启用浏览器默认XSS防护： 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时，停止渲染页面
                    .setHeader("X-XSS-Protection", "1; mode=block")
                    // 禁用浏览器内容嗅探
                    .setHeader("X-Content-Type-Options", "nosniff")
            ;
        };
    }
}
